#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

#include "datatypes.h"
#include "globals.h"
// #include "cname2id_judy.h"
#include "utils.h"

Concept* create_atomic_concept(char* name) {
	// int cid;
	Concept* c;
	// check if the atomic concept already exists
	// if ((cid = get_cid(name)) != -1)
	if ((c = get_atomic_concept((unsigned char*) name)) != NULL)
		// return atomic_concepts[cid];
		return c;
	// if it does not already exist, create it
	c = (Concept*) malloc(sizeof(Concept));
	assert(c != NULL);
	c->type = ATOMIC_CONCEPT;
	c->description.atomic = (AtomicConcept*) malloc(sizeof(AtomicConcept));
	assert(c->description.atomic != NULL);
	c->description.atomic->id = atomic_concept_count++;
	c->description.atomic->name = (char*) malloc((strlen(name) + 1) * sizeof(char));
	assert(c->description.atomic->name != NULL);
	strcpy(c->description.atomic->name, name);
	// cid = put_cname(name);
	// put_atomic_concept((unsigned char*) name, c);
	put_atomic_concept((unsigned char*) c->description.atomic->name, c);
	// c->description.concept_id = cid;
	// atomic_concepts[cid] = c;
	// return c;
	return c;
}

Concept* create_exists(Role* r, Concept* f) {
	Concept* c = (Concept*) malloc(sizeof(Concept));
	assert(c != NULL);
	c->type = EXISTENTIAL_RESTRICTION;
	c->description.exists = (Exists*) malloc(sizeof(Exists));
	assert(c->description.exists != NULL);
	c->description.exists->role = r;
	c->description.exists->filler = f;
	return c;
}

Concept* create_conjunction(int count, Concept* conjuncts[]) {
	int i;
	Concept* c = (Concept*) malloc(sizeof(Concept));
	assert(c != NULL);
	c->type = CONJUNCTION;
	c->description.conj = (Conjunction*) malloc(sizeof(Conjunction));
	assert(c->description.conj != NULL);
	c->description.conj->count = count;
	c->description.conj->conjuncts = (Concept**) malloc(count * sizeof(Concept*));
	assert(c->description.conj->conjuncts != NULL);
	for (i=0; i<count; ++i)
		c->description.conj->conjuncts[i] = conjuncts[i];

	return c;
}

Axiom* create_subclass_axiom(Concept* lhs, Concept* rhs) {
	Axiom* ax = (Axiom*) malloc(sizeof(Axiom));
	assert(ax != NULL);
	ax->type = SUBCLASS_AX;
	ax->body.subclass_ax = (SubClassAxiom*) malloc(sizeof(SubClassAxiom));
	assert(ax->body.subclass_ax != NULL);
	ax->body.subclass_ax->lhs = lhs;
	ax->body.subclass_ax->rhs = rhs;
	return ax;
}

Axiom* create_eqclass_axiom(Concept* lhs, Concept* rhs) {
	if (lhs->type != ATOMIC_CONCEPT) {
		fprintf(stderr,"the lhs of an equivalent classes axiom must be an atomic concept, aborting");
		exit(-1);
	}
	Axiom* ax = (Axiom*) malloc(sizeof(Axiom));
	assert(ax != NULL);
	ax->type = EQCLASS_AX;
	ax->body.eqclass_ax = (EqClassAxiom*) malloc(sizeof(EqClassAxiom));
	assert(ax->body.eqclass_ax != NULL);
	ax->body.eqclass_ax->lhs = lhs;
	ax->body.eqclass_ax->rhs = rhs;
	return ax;
}


Role* create_atomic_role(char* name) {
	// int rid;
	Role* r;
	// check if the atomic role already exists
	// if ((rid = get_rid(name)) != -1)
	if ((r = get_atomic_role((unsigned char*) name)) != NULL)
		// return atomic_roles[rid];
		return r;
	// if it does not already exist, create it
	r = (Role*) malloc(sizeof(Role));
	assert(r != NULL);
	r->type = ATOMIC_ROLE;
	r->description.atomic = (AtomicRole*) malloc(sizeof(AtomicRole));
	assert(r->description.atomic != NULL);
	r->description.atomic->id = atomic_role_count++;
	r->description.atomic->name = (char*) malloc((strlen(name) + 1) * sizeof(char));
	assert(r->description.atomic->name != NULL);
	strcpy(r->description.atomic->name, name);
	// rid = put_rname(name);
	put_atomic_role((unsigned char*) name, r);
	// r->description.role_id = rid;
	// atomic_roles[rid] = r;
	return r;
}

Role* create_role_composition(int size, Role* roles[]) {
	int i;
	Role* r = (Role*) malloc(sizeof(Role));
	assert(r != NULL);
	r->type = ROLE_COMPOSITION;
	r->description.role_composition = (RoleComposition*) malloc(sizeof(RoleComposition));
	assert(r->description.role_composition != NULL);
	r->description.role_composition->size = size;
	r->description.role_composition->roles = (Role**) malloc(size * sizeof(Role*));
	assert(r->description.role_composition->roles != NULL);
	for (i=0; i < size; ++i)
		r->description.role_composition->roles[i] = roles[i];

	return r;
}

Axiom* create_subrole_axiom(Role* lhs, Role* rhs) {
	Axiom* ax = (Axiom*) malloc(sizeof(Axiom));
	assert(ax != NULL);
	ax->type = SUBROLE_AX;
	ax->body.subrole_ax = (SubRoleAxiom*) malloc(sizeof(SubRoleAxiom));
	assert(ax->body.subrole_ax != NULL);
	ax->body.subrole_ax->lhs = lhs;
	ax->body.subrole_ax->rhs = rhs;
	return ax;
}
